package linker;

import manager.IMibManager;
import model.MibModule;
import model.MibNode;

import java.util.*;

public class MibNodeLinker implements INodeLinker {
    private IMibManager manager;

    private Map<String, String> nameOidMap = new HashMap<>(); // 当前所有解析过节点列表
    private HashSet<String> obsoleteSet = new HashSet<String>(); // 废弃节点列表
    private HashSet<String> existNameSet = new HashSet<String>();

    private List<MibNode> notFoundParentNodeModuleList = new LinkedList<>(); // 需要用到还未被解析到的节点列表
    // 找不到父节点的节点字典  <节点名字， 节点>
    private Map<String, MibNode> notFinishNodeMap = new HashMap<>();
    // 找不到父节点的依赖索引 <所需父节点名字， 依赖该父节点的节点列表>
    private Map<String, List<String>> notFoundParentNodeIndex = new HashMap<>();

    public MibNodeLinker(IMibManager manager) {
        this.manager = manager;
    }

    /**
     * 把mib文件中的节点模块串联起来。
     */
    @Override
    public void linkNodes(MibModule module){
        readImportModuleNodes(module.importsModuleNodesMap);
        Collection<MibNode> nodes = module.nodes.values();
        for (MibNode node : nodes){
            link(node);
        }
        for (String name : notFinishNodeMap.keySet()){
            module.nodes.remove(name);
        }
        for (String name : obsoleteSet){
            module.nodes.remove(name);
        }
    }

    /**
     * 遍历mib库依赖的模块，并导入相应的节点。
     */
    private void readImportModuleNodes(Map<String, List<String>> imports) {
        if (imports == null)
            return;
        for (Map.Entry<String, List<String>> pair : imports.entrySet()) {
            List<String> importNodeNames = pair.getValue();
            if (this.manager.isModuleExist(pair.getKey())){
                List<MibNode> moduleNodes = this.manager.getNodeListByName(pair.getKey());
                Map<String, String> oidNameMap = new HashMap<>();
                moduleNodes.forEach(node -> oidNameMap.put(node.name, node.oid)); // 创建索引
                importNodeNames.forEach(m -> {
                    char c = m.charAt(0);
                    if (c >= 'A' && c <= 'Z'){
                    }
                    else if (oidNameMap.containsKey(m))
                        this.nameOidMap.put(m, oidNameMap.get(m));
                    else
                        System.out.println(String.format("找不到节点[%s]%s", pair.getKey(), pair.getValue()));
                });// 遍历需要导入的节点，检测索引是否包含节点，包含则导入
            }else{
                System.out.println(String.format("没有找到%s模块，无法导入对应的节点模块：%s",
                        pair.getKey(), pair.getValue()));
            }

        }
    }

    /**
     * 根据缓存节点字典和当前节点的父节点名字生成完整的节点信息。
     * @param node
     */
    private void link(MibNode node) {
        if (!existNameSet.contains(node.name)) {
            String pOid;
            if (nameOidMap.containsKey(node.parentName)) { // 在所有已解析完成的节点字典中获取到父节点oid
                pOid = nameOidMap.get(node.parentName);
                node.generateInfoByParentOid(pOid);
                UpdateToCache(node);
            } else if (MibNode.isIsoNode(node.parentName)) { // 父节点是iso节点
                MibNode iso = MibNode.getIsoNode();
                UpdateToCache(iso);
                node.generateInfoByParentOid(iso.oid);
                UpdateToCache(node);
            } else if (obsoleteSet.contains(node.parentName)) { // 若父节点是废弃节点，则当前节点加入废弃节点
                discardNode(node.name);
            } else {  // 缓存到未完成字典中
                notFinishNodeMap.put(node.name, node); // 把当前节点加入到未完成字典
                if (!notFoundParentNodeIndex.containsKey(node.parentName)){
                    notFoundParentNodeIndex.put(node.parentName, new LinkedList<>());
                }
                notFoundParentNodeIndex.get(node.parentName).add(node.name); // 加入到该父节点的依赖列表中
            }
            existNameSet.add(node.name);
        } // 判断该节点名是否重复
        else {
            LogInfo(node, "该节点名重复，已跳过。");
        }
    }

    private void UpdateToCache(MibNode node) {
        nameOidMap.put(node.name, node.oid);
        UpdateNotFoundParentNodeStatus(node);
    }

    private void UpdateNotFoundParentNodeStatus(MibNode node) {
        if (notFoundParentNodeIndex.containsKey(node.name)) {
            MibNode child;
            List<String> nodeNameList = notFoundParentNodeIndex.get(node.name);
            for (String name : nodeNameList)
            {
                child = notFinishNodeMap.get(name); // 从未连接字典获取出节点
                notFinishNodeMap.remove(name); // 未完成字典移除该节点
                child.generateInfoByParentOid(node.oid);
                UpdateToCache(child);
            }

            notFoundParentNodeIndex.remove(node.name); // 把该索引删除
        } // 当前节点名是否被依赖
    }

    /**
     * 废弃指定节点。
     * 把当前节点名加入到obsolateSet，
     * 把当前节点名从notFoundParentNodeIndex中删除。
     * 把依赖于当前节点的子节点也进行废弃操作。
     * @param nodeName
     */
    private void discardNode(String nodeName){
        obsoleteSet.add(nodeName);
        if (notFoundParentNodeIndex.containsKey(nodeName))
        {
            List<String> names = notFoundParentNodeIndex.get(nodeName);
            notFoundParentNodeIndex.remove(nodeName);
            for (String name : names)
            {
                discardNode(name);
                notFinishNodeMap.remove(name);
            }
        }
    }

    private void LogInfo(Object obj, String msg) {
        String log;
        if (obj == null)
            throw new IllegalArgumentException("obj不能为空");
        if (obj instanceof MibNode)
            log = String.format("%s: %s", ((MibNode) obj).name, msg);
        else
            log = String.format("%s: %s", obj, msg);
        System.out.println(log);
    }
}
